
/* MEM.C --walks DOS MCB chain(s) : simple version  */
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
# include <string.h>
# include <dos.h>

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long ULONG;
typedef enum {FALSE,TRUE} BOOL;
typedef void far *FP;

#define MCB_FM_SEG(seg)       ((seg)-1)
#define IS_PSP(mcb)           (FP_SEG(mcb)+1==(mcb)->owner)
#define ENV_FM_PSP(psp_seg)   *((WORD far *)MK_FP(psp_seg,0x2c))

#pragma pack (1)

typedef struct {
        BYTE type;    /* M=in chain , Z=at end  */
        WORD owner;   /* PSP of the owner       */
        WORD size;    /* in 16-byte paragraphs  */
        BYTE unused [3];
        BYTE dos4 [8];
        } MCB;

void fail (char *s)  {puts (s);exit(1);}

MCB far *get_mcb (void)
    {
     __emit__(0xB4,0x52);      /*   MOV     AH,52      */
     __emit__(0xCD,0x21);      /*   INT     21         */
     __emit__(0x26);           /*   ES:                */
     __emit__(0x8B,0x57,0xFE); /*   MOV     DX,[BX-02] */
     __emit__(0x31,0xC0);      /*   XOR     AX,AX      */
    }

unsigned fstrlen (char far *s)
         {
         unsigned len = 0;
         while (*s++)
               len ++;
         return len;
         }

char far *env(MCB far *mcb)
     {
     char far *e;
     unsigned env_mcb;
     unsigned env_owner;

     if (IS_PSP(mcb))
        e=MK_FP (ENV_FM_PSP(mcb->owner),0);
     else
        return (char far *) 0;
     env_mcb = MCB_FM_SEG (FP_SEG(e));
     env_owner = ((MCB far *)MK_FP(env_mcb,0))->owner;
     return (env_owner==mcb->owner)?e:(char far *)0;
     }

char far *progname_fm_psp (unsigned psp)
     {
     char far *e;
     unsigned len;

     if (!(e=env(MK_FP(MCB_FM_SEG(psp),0))))
        return (char far *)0;
     if (_osmajor>=3)
        {
        do e+=(len=fstrlen(e))+1;
        while (len);

        if ((*((signed far *)e)>=1)&&(*((signed far *)e)<10))
           {
           e+=sizeof (signed);
           if (isalpha(*e))
              return e;
           }
        }
     return (char far *) 0;
     }

void display_progname (MCB far *mcb)
     {
     char far *s;
     if (IS_PSP(mcb))
        if (s=progname_fm_psp ((FP_SEG(mcb)+1)))
           printf (" %Fs",s);
     }

BOOL belongs (void far *vec,unsigned start,unsigned size)
     {
     unsigned seg = FP_SEG (vec) + (FP_OFF(vec)>>4);
     return (seg>=start)&&(seg<=(start+size));
     }

void display_cmdline (MCB far *mcb)
     {
     int len=*((BYTE far *)MK_FP(mcb->owner,0x80));
     char far *cmdline=MK_FP(mcb->owner,0x81);
     printf ("%.*Fs",len,cmdline);
     }

void display_vectors (MCB far *mcb)
     {
     static void far **vec=(void far **) 0;
     WORD vec_seg;
     int i;
     int did_one=0;
     if (!vec)
        {
        if (!(vec=calloc(256,sizeof(void far *))))
           fail ("insufficient memory .");
        for (i=0;i<256;i++)
            vec[i]=getvect(i);
        }
     for (i=0;i<256;i++)
         if (vec[i]&&belongs(vec[i],FP_SEG (mcb),mcb->size))
            {
            if (!did_one) {did_one++; printf ("[");}
            printf ("%02X ",i);
            vec[i]=0;
            }
         if (did_one) printf ("]");
     }

void display (MCB far *mcb)
     {

     static void far *vect_2e=(void far *)0;
     unsigned env_seg;

     printf ("%04X  %04X  %04X(%6lu)  ",
             FP_SEG (mcb),mcb->owner,mcb->size,(long)mcb->size<<4);
     if (IS_PSP(mcb))  {
        void far *e=env (mcb);
        if (env_seg = FP_SEG(e))  printf ("%04X",env_seg);
        else  printf (" ");
        display_progname (mcb);
        }
     if (!vect_2e)
        vect_2e = getvect (0x2e);
     if (!mcb->owner)
        printf ("free ");
     else if (mcb->owner == 8)
          printf ("config ");
     else if (belongs (vect_2e,FP_SEG(mcb),mcb ->size))
          printf (" %s",getenv ("COMSPEC"));
     if (IS_PSP(mcb))
        display_cmdline (mcb);
     display_vectors (mcb);
     printf ("\n");
     }

void walk (MCB far *mcb)
     {
     printf ("Seg  Owner  Size          Env\n");
     for (;;)
         switch (mcb->type)
                {
                case 'M' :
                     display (mcb);
                     mcb=MK_FP (FP_SEG (mcb)+mcb->size+1,0);
                     break;
                case 'Z' :
                     display (mcb);
                     return;
                default :
                      fail ("error in MCB chain ");
                }
      }

main (int argc,char *argv[])
     {
     if (argc<2)
        walk (get_mcb());
     else
         {
         unsigned seg;
         sscanf (argv[1],"%04X",&seg);
         walk (MK_FP(seg,0));
         }
     printf (" total memory  %dK bytes\n",biosmemory());
     return 0;
     }


